package com.crawler.search.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.crawler.search.constant.CommonColumn;
import com.crawler.search.constant.QuerierMapper;
import com.crawler.search.index.entity.QueryParam;
import com.google.common.base.CaseFormat;
import com.google.common.base.Converter;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * 查询条件拼装
 * @author zyh
 *
 */
public class BoolQueryUtil {



    /**
     * 添加must查询参数
     * @param object 查询参数
     * @param query
     * @param esField es中对应的参数字段
     * @param jsonField
     *  must:{"terms":{"title":{"华为"}}}
     */
    public static void addMust(JSONObject object, BoolQueryBuilder query, String esField, String jsonField) {
        if (Strings.isNullOrEmpty(esField)) {
            return;
        }
        JSONArray array = new JSONArray();
        if (object.containsKey(jsonField)) {
            Object o = object.get(jsonField);
            if (!(o instanceof JSONArray)) {
                array.add(o);
            } else {
                array = (JSONArray) o;
            }
            if (array.size() > 0) {
                query.must(QueryBuilders.termsQuery(esField, array));
            }
        }
    }

    /**
     * 添加must查询参数
     * @param object 查询参数
     * @param query
     * @param esField es中对应的参数字段
     * @param jsonField
     *  must:{"terms":{"title":{"华为"}}}
     */
    public static void addSegMust(JSONObject object, BoolQueryBuilder query, String esField, String jsonField) {
        if (Strings.isNullOrEmpty(esField)) {
            return;
        }
        JSONArray array = new JSONArray();
        if (object.containsKey(jsonField)) {
            Object o = object.get(jsonField);
//            if (!(o instanceof JSONArray)) {
//                array.add(o);
//            } else {
//                array = (JSONArray) o;
//            }
//            if (array.size() > 0) {
                query.must(QueryBuilders.matchQuery(esField, o.toString()));
//            }
        }
    }

    /**
     * 添加should查询参数
     * @param object 查询参数
     * @param query
     * @param esField es中对应的参数字段
     * @param jsonField
     *  must:{"terms":{"title":{"华为"}}}
     */
    public static void addShould(JSONObject object, BoolQueryBuilder query, String esField, String jsonField) {
    	if (Strings.isNullOrEmpty(esField)) {
    		return;
    	}
    	JSONArray array = new JSONArray();
    	if (object.containsKey(jsonField)) {
    		Object o = object.get(jsonField);
    		if (!(o instanceof JSONArray)) {
    			array.add(o);
    		} else {
    			array = (JSONArray) o;
    		}
    		if (array.size() > 0) {
    			for (Object obj : array) {
        			query.should(QueryBuilders.termQuery(esField, obj));
				}
    		}
    	}
    }


    /**
     * 添加must_not查询参数
     * @param object 查询参数
     * @param query
     * @param esField es中对应的参数字段
     * @param jsonField
     *  must:{"terms":{"title":{"华为"}}}
     */
    public static void addMustNot(JSONObject object, BoolQueryBuilder query, String esField, String jsonField) {
        JSONArray array = new JSONArray();
        if (object.containsKey(jsonField)) {
            Object o = object.get(jsonField);
            if (!(o instanceof JSONArray)) {
                array.add(o);
            } else {
                array = (JSONArray) o;
            }
            if (array.size() > 0) {
                query.mustNot(QueryBuilders.termsQuery(esField, array));
            }
        }
    }

    /**
     * must和 must_not添加
     * @param obj  查询参数
     * @param query
     * @param fieldMap 存储key:value-->查询参数名称：es中存储的参数名称
     * @param format
     */
    public static void addInnerMustAndNot(JSONObject obj, QueryBuilder query, Map<String, String> fieldMap, CaseFormat format) {
        if (query instanceof BoolQueryBuilder) {
            BoolQueryBuilder bool = (BoolQueryBuilder) query;
            if (obj.containsKey(QuerierMapper.MUST)) {
                JSONObject must = obj.getJSONObject(QuerierMapper.MUST);
                addMust(must, bool, fieldMap, format);
            }
            if (obj.containsKey(QuerierMapper.MUST_NOT)) {
                JSONObject mustNot = obj.getJSONObject(QuerierMapper.MUST_NOT);
                addMustNot(mustNot, bool, fieldMap, format);
            }

        }
    }

    public static void addMust(JSONObject obj, BoolQueryBuilder bool, Map<String, String> filedMap, CaseFormat format) {
        //将传参中的驼峰命名参数转换为需要的命名类型
    	//Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo(format);
        for (Entry<String, Object> entry : obj.entrySet()) {
        	String key=entry.getKey();
            if (!isKeyword(key, filedMap)) {
            	//搜索词前缀~,为非的操作
                if (key.startsWith("~")) {
                    String raw = key.substring(1);
                    if (filedMap.containsKey(raw)) {
                    	BoolQueryUtil.addMustNot(obj, bool, filedMap.get(raw), key);
                    }
                } else {
                    if (filedMap.containsKey(key)) {
                    	BoolQueryUtil.addMust(obj, bool, filedMap.get(key), key);
                    }
                }
            }
		}
    }

    public static void addSegMust(JSONObject obj, BoolQueryBuilder bool, Map<String, String> filedMap, CaseFormat format) {
        //将传参中的驼峰命名参数转换为需要的命名类型
        for (Entry<String, Object> entry : obj.entrySet()) {
        	String key=entry.getKey();
            if (!isKeyword(key, filedMap)) {
            	//搜索词前缀~,为非的操作
                if (key.startsWith("~")) {
                    String raw = key.substring(1);
                    if (filedMap.containsKey(raw)) {
                    	BoolQueryUtil.addMustNot(obj, bool, filedMap.get(raw), key);
                    }
                } else {
                    if (filedMap.containsKey(key)) {
                    	BoolQueryUtil.addSegMust(obj, bool, filedMap.get(key), key);
                    }
                }
            }
		}
    }

    public static void addShould(JSONObject obj, BoolQueryBuilder bool, Map<String, String> filedMap, CaseFormat format) {
    	//将传参中的驼峰命名参数转换为需要的命名类型
    	for (Entry<String, Object> entry : obj.entrySet()) {
    		String key=entry.getKey();
    		if (!isKeyword(key, filedMap)) {
    				if (filedMap.containsKey(key)) {
    					BoolQueryUtil.addShould(obj, bool, filedMap.get(key), key);
    				}
    		}
    	}
    }


	public static void addMustNot(JSONObject obj, BoolQueryBuilder bool, Map<String, String> filedMap, CaseFormat format) {
        Converter<String, String> converter = CaseFormat.LOWER_CAMEL.converterTo(format);
        for (Entry<String, Object> entry : obj.entrySet()) {
            String key = entry.getKey().toString();
            if (!isKeyword(key, filedMap)) {
                if (filedMap.containsKey(key)) {
                	BoolQueryUtil.addMust(obj, bool, filedMap.get(key), key);
                } else {
                	BoolQueryUtil.addMust(obj, bool, converter.convert(key), key);
                }
            }
        }

    }


    /**
     * 查询范围拼接
     * @param obj
     * @param bool
     * @param fieldMap
     * @param format
     */
    public static void addRange(JSONObject obj, BoolQueryBuilder bool, Map<String, String> fieldMap, CaseFormat format) {
        Converter<String, String> converter = CaseFormat.UPPER_CAMEL.converterTo(CaseFormat.LOWER_CAMEL);
        Converter<String, String> fieldConverter = CaseFormat.LOWER_CAMEL.converterTo(format);
        Map<String, String> beginTimeMap = new HashMap<>();
        Map<String, String> endTimeMap = new HashMap<>();
        for (Object key : obj.keySet()) {
            String beginTime = null;
            String endTime = null;
            String keyStr = key.toString();
            if(StringUtils.isNotEmpty(keyStr)){
                if (keyStr.startsWith("begin")) {
                    String field = fieldConverter.convert(
                            converter.convert(keyStr.substring("begin".length()))
                    );
                    beginTime = obj.getString(keyStr);
                    beginTimeMap.put(field, beginTime);
                } else if (keyStr.startsWith("end")) {
                    String field = fieldConverter.convert(
                            converter.convert(keyStr.substring("end".length()))
                    );
                    endTime = obj.getString(keyStr);
                    endTimeMap.put(field, endTime);
                }
            }
        }
        Set<String> fileds = new HashSet<String>();
        fileds.addAll(beginTimeMap.keySet());
        fileds.addAll(endTimeMap.keySet());
        for (String field : fileds) {
            String beginTime = beginTimeMap.get(field);
            String endTime = endTimeMap.get(field);
            field = fieldMap.getOrDefault(field, field);
            if (field.equals("time")) {
                field = QuerierMapper.FIELD_CREATE_TIME;
            }
            if(StringUtils.isNotEmpty(beginTime)&&StringUtils.isNotEmpty(endTime)) {
                bool.must
                (QueryBuilders.rangeQuery(field).format(CommonColumn.FORMAT_DAY)
                        .gte(beginTime)
                        .lte(endTime)
                );
            }else if(StringUtils.isNotEmpty(beginTime)&&StringUtils.isEmpty(endTime)) {
                bool.must
                (QueryBuilders.rangeQuery(field).format(CommonColumn.FORMAT_DAY)
                        .gte(beginTime)
                );
            }else if(StringUtils.isEmpty(beginTime)&&StringUtils.isNotEmpty(endTime)) {
                bool.must
                (QueryBuilders.rangeQuery(field).format(CommonColumn.FORMAT_DAY)
                        .lte(endTime)
                );
            }

        }

    }
    public static boolean isKeyword(String key, Map<String, String> fieldMap) {
        return QuerierMapper.keywords.contains(key)
                || key.toString().toLowerCase().endsWith(QuerierMapper.TIME)
                || key.equals(fieldMap.get(QuerierMapper.KEYWORD));
    }



    /**
     * 过滤字段
     * @param
     * @return
     */
    public static void buildRange( BoolQueryBuilder boolQuery,Map<String, JSONObject> rangeMap) {
        if(rangeMap!=null){
            for (String field : rangeMap.keySet()) {
                String begin="";
                String end="";
                JSONObject jsonObject = rangeMap.get(field);
                for (String key : jsonObject.keySet()) {
                    if(StringUtils.isNotEmpty(key)){
                        if(key.equals("beginTime|endTime")){
                            String searchValue = jsonObject.getString(key);
                            //日期筛选
                            if(StringUtils.isNotEmpty(searchValue)){
                                begin = searchValue.split("\\|")[0];
                                if(searchValue.split("\\|").length>1){
                                    end=searchValue.split("\\|")[1];
                                }
                            }
                        }else{
                            if (key.startsWith("begin")) {
                                begin=jsonObject.getString(key);
                            }else if(key.startsWith("end")){
                                end=jsonObject.getString(key);
                            }
                        }

                    }
                }
                if(field.toLowerCase().contains("time")||field.toLowerCase().contains("date")){
                    RangeQueryBuilder format = QueryBuilders.rangeQuery(field).format(CommonColumn.FORMAT_DAY);
                    boolean flag=false;
                    if(StringUtils.isNotEmpty(begin)){
                        format.gte(begin);
                        flag=true;
                    }
                    if(StringUtils.isNotEmpty(end)){
                        format.lte(end);
                        flag=true;
                    }
                    if(flag){
                        boolQuery.must(format);
                    }else{
                        if(jsonObject.containsKey(QuerierMapper.FORMAT)){
                            format = QueryBuilders.rangeQuery(field).format(jsonObject.getString(QuerierMapper.FORMAT));
                            format.gte(jsonObject.getString(field));
                            String endDate = jsonObject.getString(field);
                            format.lt(Integer.parseInt(endDate)+1);
                            boolQuery.must(format);
                        }
                    }
                }
            }
        }
    }

}
